﻿#region Using

using System;
using System.Collections.Generic;
using System.Linq;

using Common.Base;
using Common.Enums;

using CommunicationLibrary.TransportData;
using CommunicationLibrary.TransportData.Enums;

using GameCommon.HitBoxes;
using GameCommon.Manager;

using GameGraphics.Components;
using GameGraphics.Enums;

using GameNetwork.Network;

using Microsoft.Xna.Framework;

using Route = GameGraphics.Components.Route;

#endregion

namespace GameGraphics.Helper
{
    internal static class BoardBuilder
    {
        /// <summary>
        /// Initilialisiert das Board
        /// Lädt die Hexagontextur, positioniert die Tiles und fügt sie zur ComponentCollection hinzu
        /// </summary>
        /// <param name="playerId"> Player Id </param>
        /// <param name="tiles"> Liste der Tiles vom GameState </param>
        /// <returns> List of BoardTiles </returns>
        public static Dictionary<int, BoardTile> BuildBoard(int playerId, IEnumerable<Tile> tiles)
        {
            var boardTiles = new Dictionary<int, BoardTile>();

            var tileList = tiles.ToList();
            var tileBorders = new Position();

            foreach (var tile in tileList)
            {
                if (tile.Position.X > tileBorders.X)
                {
                    tileBorders.X = tile.Position.X;
                }

                if (tile.Position.Y > tileBorders.Y)
                {
                    tileBorders.Y = tile.Position.Y;
                }
            }

            foreach (var tile in tileList)
            {
                boardTiles.Add(tile.Identifier, GetBoardTile(playerId, tile, tileBorders));
            }

            return boardTiles;
        }

        public static void Update(int playerId, IEnumerable<Tile> tiles, Dictionary<int, BoardTile> boardTiles)
        {
            foreach (var tile in tiles)
            {
                boardTiles[tile.Identifier].Update(playerId, tile);
            }
        }

        public static Route GetRoute(BoardTile startTile, BoardTile endTile, RouteTypeEnum routeType, Dimension dimension)
        {
            var direction = ArrowDirectionHelper.GetArrowDirection(startTile.GridPosition, endTile.GridPosition);
            var tex = Managers.ContentManager.GetBoardTexture2D(string.Format(@"Arrow\{0}", (int)direction));
            var boardroute = new Route(string.Format("R_{0}", startTile), tex, routeType, startTile, endTile);
            boardroute.Dimension.Position = ArrowDirectionHelper.GetArrowPosition(direction, dimension, boardroute.Size);

            return boardroute;
        }

        /// <summary>
        /// Lädt das BoardTile und positioniert es
        /// </summary>
        /// <param name="id">Player Id</param>
        /// <param name="tile">BoardTile aus dem GameState</param>
        /// <param name="tileBorders">Maximaler X & Y Index</param>
        /// <returns>Fertig positioniertes (linksbündig) BoardTile</returns>
        private static BoardTile GetBoardTile(int id, Tile tile, Position tileBorders)
        {
            var textureName = GetTextureName(tile.Building.BuildingType);
            var boardTile = new BoardTile(string.Format("BT_{0}", tile.Position), Managers.ContentManager.GetBoardTexture2D("FreeSpace", GetZoom()));

            var y = Math.Abs(tile.Position.Y - tileBorders.Y);
            var startY = -((tileBorders.X * boardTile.Size.Height) / 4);
            
            boardTile.Dimension.Position = TilePositionCalculator.GetPosition(tile.Position.X, y, startY, boardTile.Size);
            
            boardTile.ShowFarmerRoutes();
            boardTile.GridPosition = new Position(tile.Position);
            boardTile.Layer = y + 1;

            if (tile.Owner.Identifier == id)
            {
                boardTile.Conquer();
            }

            SetHitBox(boardTile);
            CenterTile(boardTile, tileBorders);
            SetHitpointText(boardTile, tile.Hitpoints);

            boardTile.InitializeHighlight(Managers.ContentManager.GetBoardTexture2D("Border", GetZoom()));

            return boardTile;
        }

        private static void SetHitpointText(BoardTile boardTile, int hitpoints)
        {
            var hitpointText = new Hitpoints(string.Format("HP_{0}", boardTile.GridPosition), FontSizeEnum.S12, FontEnum.PressStart);
            var x = (int)Math.Round(boardTile.Dimension.X + ((boardTile.Dimension.Width / 3) * 0.75));
            var y = boardTile.Dimension.Y + 5;

            hitpointText.Dimension = new Dimension(x, y, boardTile.Dimension.Size);
            hitpointText.Value = hitpoints.ToString();

            boardTile.HitPoints = hitpointText;
        }

        /// <summary>
        /// Erstellt die Hitboxen für die Tiles. Die Dimension wird als Referenz übergeben.
        /// </summary>
        /// <param name="boardTile"> The board Tile. </param>
        private static void SetHitBox(BoardTile boardTile)
        {
            var dimension = new Dimension(boardTile.Dimension.Position, boardTile.Dimension.Width, boardTile.Dimension.Height - 8);

            boardTile.HitBox = new HexagonHitBox(string.Format("HHB_{0}", boardTile.GridPosition), dimension, "Tile");
        }

        /// <summary>
        /// Zentriert die Tiles
        /// </summary>
        /// <param name="boardTile"></param>
        /// <param name="tileBorders">Maximaler X & Y Index</param>
        private static void CenterTile(BoardTile boardTile, Position tileBorders)
        {
            var boardWidth = boardTile.Size.Width * 0.75 * (tileBorders.X + 1);
            var screenWidth = Managers.ContentManager.GetViewportWidth();

            if (screenWidth < boardWidth)
            {
                return;
            }

            var offset = (int)Math.Round((screenWidth - boardWidth) / 2);

            boardTile.Position.X += offset;
        }

        private static int GetZoom()
        {
            //// TODO Add Logic for LevelOfDetail
            return 1;
        }

        private static string GetTextureName(BuildingTypeEnum buildingType)
        {
            if (buildingType == BuildingTypeEnum.None)
            {
                return "FreeSpace";
            }

            return buildingType.ToString();
        }
    }
}